﻿#pragma once
#ifndef _SOCKET_H_
#define _SOCKET_H_


#ifdef _WIN32
#include <string>

#else
#include <sys/socket.h>
#include <string.h>
#endif

#include <memory>
#include <functional>

#include "as_address.h"


#ifdef WIN32
typedef SOCKET socket_fd;
typedef int *socket_len;
#define SOCKET_ERR_FD INVALID_SOCKET 
#define AS_SD_BOTH SD_BOTH
#define AS_SD_SEND SD_SEND
#define AS_SD_RECV SD_RECV

#else
typedef int socket_fd;
typedef socklen_t *socket_len;
#define SOCKET_ERR_FD -1
#define AS_SD_BOTH SHUT_RDWR
#define AS_SD_SEND SHUT_WR
#define AS_SD_RECV SHUT_RD
#endif


namespace as
{
	namespace net
	{
		class Socket
		{
		public:
			Socket(socket_fd fd = SOCKET_ERR_FD);
			~Socket() {}
			static socket_fd create_socket(int af);
			int bind(const Address &addr);
			int connect(const Address &addr);
			int listen();

			void close();
			static void close(socket_fd fd);

			void shutdown(int how);
			static void shutdown(socket_fd fd, int how);

			void set_non_block();
			static void set_non_block(socket_fd fd);
			void set_keep_alive();
			static void set_keep_alive(socket_fd fd);

			void set_recv_buff(int size);
			static void set_recv_buff(socket_fd fd, int size);

			void set_send_buff(int size);
			static void set_send_buff(socket_fd fd, int size);

			socket_fd accept(const Address &peekAddr);
			static socket_fd accept(socket_fd fd, sockaddr *addr, socket_len len);

			int write(const void *buf, int size);
			static int write(socket_fd fd, const void *buf, int size);
			int recv(void *buf, int size);
			static int recv(socket_fd fd, void *buf, int size);

			int get_last_err();
			static int get_last_err(socket_fd fd);

			static Address get_local_addr(socket_fd fd);
			static Address get_peer_addr(socket_fd fd);

			socket_fd get_fd() { return fd_; }
			void set_fd(socket_fd fd);
		private:
			socket_fd fd_;
		};
	}
}

#endif